
/*
 XMail OSAX -- Copyright (C) 2004, 2005, 2006, 2007 Jean-Baptiste LE STANG osax@lestang.org
 
	
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 */


#include <pcre.h>
#include <pcre.h>

#include "mail-utils.h"
#include "mail-mimes.h"


char * extractWithLastDelimiter(const char * string, char delimiter){
	unsigned int pos = 0;
	unsigned int data_size = 0;
	
	char * extension = NULL;
	if (string == NULL) return NULL;
	data_size = strlen(string);
	pos = data_size;
	
	while(pos > 0){
		if (string[pos] == delimiter){
			if (pos == strlen(string)){
				return NULL;
			} else {
				extension = (char *) malloc(sizeof(char)*(data_size-pos));
				memset(extension,0,(data_size-pos));
				strncpy(extension,string+pos+1,(data_size-pos));
				break;
			}
		} else {
			pos--;
		}
	}
	return extension;
	
}

char * findFileNameWithFilePath(const char * path){
	return extractWithLastDelimiter(path,'/');
}

char * findMimeWithFilePath(const char * path){
	char * lastComponent = extractWithLastDelimiter(path,'.');
	char * mime = findMimeWithExtension(lastComponent);
	if (lastComponent != NULL) free(lastComponent);
	return mime;
}

char * findMimeWithExtension(char * extension){
	int i = 0;
	int nb = sizeof(mimes)/sizeof(mime);
	if (extension == NULL) return findMimeWithExtension("unknown");
	
	for (i = 0 ; i < nb ; i++){
		if (strcmp(mimes[i].extension,extension)==0) return mimes[i].mime_type;
	}
	return "xmail/xmail-unknown";
}


void appendBytesToString(growing_buffer * buffer,char * data, unsigned int nbytes){
	unsigned int alloc_size = 1024;
	unsigned int increase_size = 0;
	
	if (buffer->length <= buffer->current_length + nbytes){
		increase_size = ((nbytes/alloc_size)*alloc_size+alloc_size);
		if (buffer->data != NULL){
			buffer->data = realloc(buffer->data,buffer->length+increase_size);
			memset(buffer->data+buffer->current_length,0,increase_size);
		} else {
			buffer->data = malloc(increase_size);
			memset(buffer->data,0,increase_size);
		}
	}
	memcpy(buffer->data+buffer->current_length,data,nbytes);
	buffer->length += increase_size;
	buffer->current_length += nbytes;
    
}

void appendString(growing_buffer * buffer,char * data){
    if(data != NULL){
        appendBytesToString(buffer,data,strlen(data));
    }
}

void appendChar(growing_buffer * buffer,char c){
	appendBytesToString(buffer,&c,1);
}

int is7BitSafe(char * str){
	unsigned int i = 0;
	for ( i = 0 ; i < strlen(str) ; i++){
		if (str[i] > 0x007E || str[i] < 0 ) return 0;
	}
	return 1;
}

char * genericEncoder(char * encoderName, char * orig_str){
    unsigned int oversize = strlen(encoderName)+strlen("==????B");
	unsigned int orig_len = 0;
    unsigned int real_size = 0;
	char * buffer = NULL;
	char * dest_buffer = NULL;
	
    if (orig_str == NULL) return NULL;
    
	if (is7BitSafe(orig_str)) return strdup(orig_str);
    
	orig_len = strlen(orig_str);
    real_size = base64encode(orig_str, &dest_buffer,orig_len);
    
    if (dest_buffer != NULL){
        buffer = (char * )malloc(sizeof(char)*(real_size+oversize+1));
        sprintf(buffer,"=?%s?B?%s?=",encoderName,dest_buffer);
        free(dest_buffer);
    }
	return buffer;
}

char * encodeWithCharsetAndAlgo(char * orig_str, char * charset, unsigned int block_size,EncodingAlgorithm algo){	
	unsigned int oversize = strlen(charset)+7;
	unsigned int orig_len = 0;
    unsigned int chunck_size = (block_size-oversize);
    unsigned int nb_chunks = 0;
    //EncodingAlgorithm algo = Base64Algorithm;
	char * buffer = NULL;
	char * dest_buffer = NULL;
    char * initial_position = NULL;
    
    if (orig_str == NULL) return NULL;
	if (is7BitSafe(orig_str)) return strdup(orig_str);
    
	orig_len = strlen(orig_str);
    unsigned int real_size = 0;
    
    if (algo == Base64Algorithm){
        real_size = base64encode(orig_str, &dest_buffer,orig_len);
    } else if (algo == QuotedPrintableAlgorithm){
        real_size = quotedPrintableEncode(orig_str,&dest_buffer,0);
    }
    initial_position = dest_buffer;
    
    chunck_size = 24;
    nb_chunks = orig_len / chunck_size + ((orig_len - orig_len/chunck_size) != 0);
    unsigned int final_size = nb_chunks*(block_size+1)+1;

    buffer = (char * )malloc(sizeof(char)*(final_size));
    memset(buffer,0,sizeof(char)*(final_size));
    char * current_chunk = (char *) malloc((chunck_size+1)*sizeof(char));
    
    while(nb_chunks>0){
        memset(current_chunk,0,(chunck_size+1)*sizeof(char));
        if (chunck_size > strlen(orig_str)){
            chunck_size = strlen(orig_str);
        } 
        
        memcpy(current_chunk,orig_str,chunck_size);
        
        real_size = base64encode(current_chunk, &dest_buffer,chunck_size);
        
        if (buffer[0] != 0){
            sprintf(buffer,"%s =?%s?%c?%s?=",buffer,charset,algo,dest_buffer);
        } else {
            sprintf(buffer,"=?%s?%c?%s?=",charset,algo,dest_buffer);
        }
        free(dest_buffer);
        orig_str += chunck_size;
        nb_chunks--;
    }
    return buffer;
}

char * utf8GetNextCharSize(char * str){
	return 0;
}

char * encodeutf8With76Chars(char * orig_str){
    return encodeWithCharsetAndAlgo(orig_str,"UTF-8",76,Base64Algorithm);
}

char * encodeutf8(char * orig_str){	
	return genericEncoder("UTF-8",orig_str);
}

char * encodewindows1252(char * orig_str){
    return genericEncoder("windows-1252",orig_str);
}

char   * encodewindows1252with76Chars(char * orig_str){
    return encodeWithCharsetAndAlgo(orig_str,"windows-1252",76,Base64Algorithm);
}

char * encodeiso88591(char * orig_str){
    return genericEncoder("ISO-8859-1",orig_str);
}

char   * encodeiso88591with76Chars(char * orig_str){
    return encodeWithCharsetAndAlgo(orig_str,"ISO-8859-1",76,Base64Algorithm);
}

char * encodeusascii(char * orig_str){
    return genericEncoder("US-ASCII",orig_str);
}

char   * encodeusasciiwith76Chars(char * orig_str){
    return encodeWithCharsetAndAlgo(orig_str,"US-ASCII",76,Base64Algorithm);
}


void strcpy_wrapper(char ** dest, char * source){
	if(*dest == NULL){
		*dest = (char *)malloc(sizeof(char)*strlen(source));
	} else {
		*dest = (char *)realloc(dest,sizeof(char)*strlen(source));
	}
	if (*dest != NULL) strcpy(*dest, source);
}

char * newbound(const char * input){
	unsigned char digest[16];
	char * bounds = NULL;
	int j = 0;
	
	alg_chksum((unsigned char *)input, strlen(input), (unsigned char *)digest,H_MD5);
	bounds = (char *)malloc(sizeof(char)*40); 
	
	for(j = 0 ; j < 16 ; j++){
		sprintf(bounds,"bounds=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
				digest[0],digest[1],digest[2],digest[3],digest[4],digest[5],digest[6],digest[7],digest[8],
				digest[9],digest[10],digest[11],digest[12],digest[13],digest[14],digest[15]);
	}
	bounds[32] = 0;
	return bounds;
}

void matchEmailAndName(char * subject,char ** name,char ** email){
	pcre *re = NULL;
	const char *error = NULL;
	int erroffset = 0;
	int ovector[30];
	int subject_length = 0;
	int rc = 0;
	int nameL = 0;
	int emailL = 0;
	
    
	char * pattern = "^((.*)<)*([-!#$%&'*+\\./0-9=?A-Z^_`a-z{|}~]+@[-!#$%&'*+\\/0-9=?A-Z^_`a-z{|}~]+\\.[-!#$%&'*+\\./0-9=?A-Z^_`a-z{|}~]+)>*$";
	
	subject_length = (int)strlen(subject);
	re = pcre_compile(pattern,PCRE_UTF8,&error,&erroffset,NULL);
	
	if (re == NULL){
		*email = NULL;
        *name=NULL;
		return;
	}
	
	/* the compiled pattern */
	/* no extra data - we didn't study the pattern */
	/* the subject string */
	/* the length of the subject */
	/* start at offset 0 in the subject */
	/* default options */
	/* output vector for substring information */
	/* number of elements in the output vector */
	
	rc = pcre_exec(re,NULL,subject,subject_length,0,0,ovector,30);
	
	/* Matching failed: handle error cases */
	
	if (rc < 0){
		switch(rc){
			case PCRE_ERROR_NOMATCH: /*fprintf(stdout,"No match\n");*/ break;
			default: /*fprintf(stdout,"Matching error %d\n", rc);*/ break;
		}
		if (re != NULL) free(re);     /* Release memory used for the compiled pattern */
        
		email = NULL;name=NULL;
		return;
	}
    
	nameL = ovector[2*2+1] - ovector[2*2];
	if (nameL>0){
        if( name != NULL){
            *name = (char *)malloc(sizeof(char)*(nameL+1));
            strncpy(*name,subject + ovector[2*2],nameL);
            (*name)[nameL] = 0;
        }
    }
	
	emailL = ovector[2*3+1] - ovector[2*3];
	if(emailL>0){
        if (email != NULL){
            *email = (char *)malloc(sizeof(char)*(emailL+1));
            strncpy(*email,subject + ovector[2*3],emailL);
            (*email)[emailL] = 0;
        }
	}
    
    
	if (re != NULL) free(re);
}
